package tests.datastructures.stacks;

import static org.junit.Assert.*;

import java.util.Iterator;
import java.util.NoSuchElementException;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import datastructures.stacks.ArrayStack;
import datastructures.stacks.StackADT;

public class ArrayStackTestCase {

	private StackADT<String> stack;

	@Before
	public void setUp() throws Exception {
		 this.stack = new ArrayStack<String>(3);
	}

	@After
	public void tearDown() throws Exception {
		this.stack = null;
	}

	@Test
	public void testInitialInstance() {
		assertEquals(0, this.stack.size());
		assertTrue(this.stack.isEmpty());
	}

	@Test
	public void testNormal() {
		// There is a element
		String testValue = "Gatsby";
		this.stack.push(testValue);
		assertEquals(1, this.stack.size());
		assertFalse(this.stack.isEmpty());
		assertEquals(testValue, this.stack.peek());
		assertEquals(testValue, this.stack.pop());
		assertEquals(0, this.stack.size());
		assertTrue(this.stack.isEmpty());

		// There is a element
		String testValue1 = "Gatsby";
		String testValue2 = "is";
		String testValue3 = "best";
		this.stack.push(testValue1);
		this.stack.push(testValue2);
		this.stack.push(testValue3);
		assertEquals(3, this.stack.size());
		assertEquals(testValue3, this.stack.pop());
		assertEquals(testValue2, this.stack.pop());
		assertEquals(testValue1, this.stack.pop());
		assertEquals(0, this.stack.size());
		assertTrue(this.stack.isEmpty());
	}

	@Test
	public void testArrayStackExpension() {
		// There is a element
		String testValue1 = "Gatsby";
		String testValue2 = "is";
		String testValue3 = "best";
		String testValue4 = "^^";
		this.stack.push(testValue1);
		this.stack.push(testValue2);
		this.stack.push(testValue3);
		this.stack.push(testValue4);
		assertEquals(4, this.stack.size());
		assertEquals(testValue4, this.stack.pop());
		assertEquals(testValue3, this.stack.pop());
		assertEquals(testValue2, this.stack.pop());
		assertEquals(testValue1, this.stack.pop());
		assertTrue(this.stack.isEmpty());
		assertEquals(null, this.stack.peek());
		assertEquals(null, this.stack.pop());
	}

	@Test
	public void testRetrievingDataFromEmptyStack() {
		// When the stack is empty, then null will be returned
		assertEquals(null, this.stack.peek());
		assertEquals(null, this.stack.pop());
	}

	@Test
	public void testIterator() {
		// There is a element
		String testValue1 = "Gatsby";
		String testValue2 = "is";
		String testValue3 = "best";
		String testValue4 = "^^";
		this.stack.push(testValue1);
		this.stack.push(testValue2);
		this.stack.push(testValue3);
		this.stack.push(testValue4);

		String[] tmpValue = {testValue1, testValue2, testValue3, testValue4};

		//shorthand
		int topIndex = this.stack.size();
		for (String s : this.stack) {
			assertEquals(tmpValue[--topIndex], s);
		}

		//longhand
		topIndex = this.stack.size();
		Iterator<String> iterator = this.stack.iterator();
		while (iterator.hasNext()) {
			String s = iterator.next();
			assertEquals(tmpValue[--topIndex], s);
		}
	}

	@Test(expected=NoSuchElementException.class)
	public void testIteratorWithNoSuchElementException() {
		Iterator<String> iterator = this.stack.iterator();
		iterator.next();
	}

	@Test(expected=UnsupportedOperationException.class)
	public void testRemoveInIteratorWithUnsupportedOperationException() {
		Iterator<String> iterator = this.stack.iterator();
		iterator.remove();
	}
}
